package redis_task

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	log "github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
	"os"
	"strings"
	"time"
)

var (
	ctx          = context.Background()
	g_rdb_remote *redis.Client //only use for feedback =

	G_task_chanel = make(chan []redis.XStream, 1024)
)

type UpdateConf struct {
	RedisAddr string `yaml:"redis_addr"`
	RedisAuth string `yaml:"redis_auth"`
}

func getConf() (*UpdateConf, error) {
	c := new(UpdateConf)
	yamlFile, err := os.ReadFile("config.yaml")
	if err != nil {
		//log.Error(err)
		return nil, err
	}
	err = yaml.Unmarshal(yamlFile, c)
	if err != nil {
		//log.Error(err)
		return nil, err
	}
	return c, nil
}

func SetRedisConfig(addr string, pass string) error {
	conf, err := getConf()
	if err != nil {
		log.Error(err)
		return err
	} else {
		conf.RedisAddr = addr
		conf.RedisAuth = pass
		data, err := yaml.Marshal(conf)
		if err != nil {
			log.Error(err)
			return err
		} else {
			os.WriteFile("config.yaml", data, 0666)
		}
	}
	return nil
}

func init() {
	conf, err := getConf()
	if err != nil {
		log.Error(err)
		os.Exit(1)
	}

	g_rdb_remote = redis.NewClient(&redis.Options{
		Addr:        conf.RedisAddr,
		Password:    conf.RedisAuth, // no password set
		DB:          0,              // use default DB
		DialTimeout: 30 * time.Second,
		ReadTimeout: time.Minute,
	})
	_, err = g_rdb_remote.Ping(ctx).Result()
	if err != nil {
		log.Error(err)
	} else {
		log.Trace("connect to remote redis success")
	}
}

func initDomainInfo(domain_format string) error {
	dataArray, err := getInitDataFromRedis(domain_format)
	if err != nil {
		log.Error(err)
		return err
	} else {
		for _, s := range dataArray {
			after := strings.Split(s, "_")
			if len(after) != 2 {
				continue
			}

			value, err := g_rdb_remote.Get(ctx, s).Result()
			if err != nil {
				log.Error(err)
			}

			//TODO
			log.Trace(value)
		}
	}

	return nil
}

func getTaskFromRedis(stream_name string) {
	var TailId = "$"
	for {
		func() {
			defer func() {
				if err := recover(); err != nil {
					log.Error(err)
				}
			}()

			task, err := g_rdb_remote.XRead(ctx, &redis.XReadArgs{
				Streams: []string{stream_name, TailId},
				Block:   5 * time.Second,
			}).Result()
			if err != nil {
				return
			} else {
				log.Trace("get task from redis: ", task)
			}

			if len(task) > 0 {
				messages := task[len(task)-1].Messages
				TailId = messages[len(messages)-1].ID

				G_task_chanel <- task
			}

		}()
	}
}
func GetTaskFromRedis(stream_name string) {
	getTaskFromRedis(stream_name)
}

func getInitDataFromRedis(r string) ([]string, error) {
	//recursive get from redis scan
	data := make([]string, 0)
	var cursor uint64
	for true {
		dataArray, c, err := g_rdb_remote.Scan(ctx, cursor, r, 10000).Result()
		log.Tracef("getInitDataFromRedis cursor: %d, len: %d", c, len(dataArray))
		if err != nil {
			log.Error(err)
			break
		}

		//log.Tracef("get data from redis: %s", dataArray)
		if len(dataArray) > 0 {
			//log.Tracef("get data from redis: %s", dataArray)
			data = append(data, dataArray...)
			cursor = c
			log.Tracef("getInitDataFromRedis from redis: %d", len(data))
		}

		if len(dataArray) == 0 && c != 0 {
			cursor = c
			continue
		}

		if c == 0 {
			break
		}
	}

	if len(data) > 0 {
		return data, nil
	}

	return nil, fmt.Errorf("get data from redis failed")
}

func GetInitDataFromRedis(r string) ([]string, []string, error) {
	//recursive get from redis scan
	keys := make([]string, 0)
	values := make([]string, 0)
	var err error

	keys, err = getInitDataFromRedis(r)
	if err != nil {
		log.Error(err)
		return nil, nil, err
	} else {
		log.Tracef("getInitDataFromRedis keys: %v", keys)
	}

	if len(keys) > 0 {
		for _, key := range keys {
			value, err := g_rdb_remote.Get(ctx, key).Result()
			if err != nil {
				log.Error(err)
			} else {
				values = append(values, value)
			}
		}

		return keys, values, nil
	}

	return nil, nil, fmt.Errorf("get data from redis failed")
}

